package dungeonElements;

import org.junit.*;
import static org.junit.Assert.*;

import java.math.BigDecimal;
import dungeonTools.Direction;
import temperature.Temperature;
import temperature.TemperatureScale;

/**
 * @author Tom Jacobs & Ewoud De Moor
 * @version 3.0
 */
public class SquareTest {

	public static Square square;
	public static Square otherSquare;
	
	@Before
	public void setUp() throws Exception {
		square = new NormalSquare();
		otherSquare = new NormalSquare();
	}

	@After
	public void tearDown() throws Exception {
		if(!square.isTerminated()){
			assertTrue(square.hasProperBorders());
			assertTrue(square.canHaveAsTemperature(square.getTemperature()));
			assertTrue(Square.isValidHumidity(square.getHumidity()));
		}
		if(!otherSquare.isTerminated()){
			assertTrue(otherSquare.hasProperBorders());
			assertTrue(otherSquare.canHaveAsTemperature(otherSquare.getTemperature()));
			assertTrue(Square.isValidHumidity(otherSquare.getHumidity()));
		}
	}

	@Test
	public void terminateTest(){
		Border border = square.getBorder(Direction.FLOOR);
		square.terminate();
		assertEquals(true, square.isTerminated());
		assertEquals(true, border.isTerminated());
		for(Direction direction : Direction.values() ){
			assertEquals(false, square.hasBorderInDirection(direction));
			assertNull( square.getBorder(direction));
			assertEquals(false, border.hasSquareInDirection(direction));
		}
	}
	
	@Test
	public void terminate_withSharedBorders(){
		Border border = square.getBorder(Direction.FLOOR);
		otherSquare.setBorder(border, Direction.CEILING);
		square.terminate();	
		assertEquals(true, square.isTerminated());
		assertEquals(false, border.isTerminated());
		assertEquals(false, border.hasSquareInDirection(Direction.CEILING));
		assertEquals(true, border.hasSquareInDirection(Direction.FLOOR));
		for(Direction direction : Direction.values() ){
			assertEquals(false, square.hasBorderInDirection(direction));
			assertNull( square.getBorder(direction));
		}
	}
	
	@Test
	public void setTemperature_Correctly(){
		square.setTemperature(Temperature.CELSIUS_0);
		assertEquals(Temperature.CELSIUS_0, square.getTemperature());
		Temperature aTemperature = new Temperature(BigDecimal.valueOf(273.16),TemperatureScale.KELVIN);
		square.setTemperature(aTemperature);
		assertEquals(aTemperature,square.getTemperature());
	}	
	
	@Test
	public void setTemperature_ToLow(){
		assertEquals(false, square.canHaveAsTemperature(Temperature.ABSOLUTE_ZERO));
	}
	
	@Test
	public void setTemperature_ToHigh(){
		Temperature highTemperature = new Temperature(BigDecimal.valueOf(Long.MAX_VALUE));
		assertEquals(square.canHaveAsTemperature(highTemperature), false);
	}
	
	@Test
	public void setMaxTemperature_Correctly(){
		Temperature highTemperature = new Temperature(BigDecimal.valueOf(Long.MAX_VALUE));
		square.setMaxTemperature(highTemperature);
		assertTrue(highTemperature.compareTo(square.getMaxTemperature())==0);
	}
	
	@Test
	public void setMinTemperature_Correctly(){
		square.setMinTemperature(Temperature.ABSOLUTE_ZERO);
		assertTrue(Temperature.ABSOLUTE_ZERO.compareTo(square.getMinTemperature())==0);
	}
	
	@Test
	public void coldDamageValues(){
		square.setTemperature(Temperature.CELSIUS_0);
		assertEquals(square.getColdDamage(),0);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-5),TemperatureScale.CELSIUS));
		assertEquals(square.getColdDamage(),0);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-15),TemperatureScale.CELSIUS));
		assertEquals(square.getColdDamage(),1);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-20),TemperatureScale.CELSIUS));
		assertEquals(square.getColdDamage(),1);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-25),TemperatureScale.CELSIUS));
		assertEquals(square.getColdDamage(),2);
	}
	
	@Test
	public void heatDamageValues(){
		square.setTemperature(Temperature.CELSIUS_0);
		assertEquals(square.getHeatDamage(),0);
		square.setTemperature(new Temperature(BigDecimal.valueOf(35),TemperatureScale.CELSIUS));
		assertEquals(square.getHeatDamage(),0);
		square.setTemperature(new Temperature(BigDecimal.valueOf(50),TemperatureScale.CELSIUS));
		assertEquals(square.getHeatDamage(),1);
		square.setTemperature(new Temperature(BigDecimal.valueOf(64),TemperatureScale.CELSIUS));
		assertEquals(square.getHeatDamage(),1);
		square.setTemperature(new Temperature(BigDecimal.valueOf(65),TemperatureScale.CELSIUS));
		assertEquals(square.getHeatDamage(),2);
	}
	@Test(expected = IllegalArgumentException.class)
	public void heatDamageThreshold_toLow(){
		Square.setHeatDamageThreshold(-6);
	}
	
	@Test
	public void setHeatDamageThreshold(){
		Square.setHeatDamageThreshold(0);
		assertEquals(0,Square.getHeatDamageThreshold());
		Square.setHeatDamageThreshold(35);
	}
	
	@Test(expected = IllegalArgumentException.class)
	public void heatDamageFactor_toLow(){
		Square.setHeatDamageFactor(-6);
	}
	
	@Test(expected = IllegalArgumentException.class)
	public void heatDamageFactor_ZERO(){
		Square.setHeatDamageFactor(0);
	}
	
	@Test
	public void setHeatDamageFactor(){
		Square.setHeatDamageFactor(3);
		assertEquals(3,Square.getHeatDamageFactor());
		Square.setHeatDamageFactor(15);
	}
	
	@Test(expected = IllegalArgumentException.class)
	public void setTemperature_invalidTemperature(){
		square.setTemperature(new Temperature(BigDecimal.valueOf(-1337)));
	}
	
	@Test
	public void setHumidity_Correctly(){
		square.setHumidity(3);
		assertEquals(3.00d,square.getHumidity(),0.0000008d);
	}
	
	@Test
	public void humidity_ToLow(){
		assertEquals(Square.isValidHumidity(-1),false);
	}
	
	@Test
	public void humidity_ToHigh(){
		assertEquals(Square.isValidHumidity(104),false);
	}
	
	@Test
	public void humidity_invalidPrecision(){
		assertEquals(Square.isValidHumidity(0.001),false);
	}
	
	@Test
	public void causesRustDamage(){
		square.setHumidity(3);
		assertEquals(square.causesRustDamage(),false);
		square.setHumidity(31);
		assertEquals(square.causesRustDamage(),false);
		square.setHumidity(37);
		assertEquals(square.causesRustDamage(),true);
	}
	
	@Test
	public void rustDamageValues(){
		square.setHumidity(3);
		assertEquals(square.getRustDamage(),0);
		square.setHumidity(31);
		assertEquals(square.getRustDamage(),0);
		square.setHumidity(37);
		assertEquals(square.getRustDamage(),1);
	}
	
	@Test
	public void inherintlySplippery_True(){
		square.setHumidity(99);
		square.setTemperature(new Temperature(BigDecimal.valueOf(1)));
		square.setSlipperySurface(true);
		assertEquals(square.isSlippery(),true);
	}
	@Test
	public void inherintlySplippery_False(){
		square.setHumidity(99);
		square.setTemperature(new Temperature(BigDecimal.valueOf(1)));
		square.setSlipperySurface(false);
		assertEquals(false,square.isSlippery());
	}
	
	@Test
	public void isSlippery_All(){
		square.setHumidity(100);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-20)));
		square.setSlipperySurface(true);
		assertEquals(square.isSlippery(),true);
	}
	
	@Test
	public void isSlippery_FullHumidity(){
		square.setHumidity(100);
		square.setTemperature(new Temperature(BigDecimal.valueOf(20)));
		square.setSlipperySurface(false);
		assertEquals(square.isSlippery(),true);
	}
	
	@Test
	public void isSlippery_Ice(){
		square.setHumidity(12);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-20)));
		square.setSlipperySurface(false);
		assertEquals(square.isSlippery(),true);
	}
	@Test
	public void isSlippery_NoIce(){
		square.setHumidity(9);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-20)));
		square.setSlipperySurface(false);
		assertEquals(square.isSlippery(),false);
	}
	
	@Test
	public void isSlippery_NotEnoughHumidity(){
		square.setHumidity(99.99);
		square.setTemperature(new Temperature(BigDecimal.valueOf(1000)));
		square.setSlipperySurface(false);
		assertEquals(square.isSlippery(),false);
	}
	
	@Test
	public void inhabitability_Heat(){
		square.setHumidity(100);
		square.setTemperature(new Temperature(BigDecimal.valueOf(185)));
		assertEquals(-31.62277d,square.getInhabitability(),0.001d);
	}
	@Test
	public void inhabitability_Cold(){
		square.setHumidity(100);
		square.setTemperature(new Temperature(BigDecimal.valueOf(-45)));
		assertEquals(-2.0d,square.getInhabitability(),0.001d);
	}
	@Test
	public void inhabitability_GoodTemperature(){
		square.setHumidity(100);
		square.setTemperature(new Temperature(BigDecimal.valueOf(20)));
		assertEquals(0.0d,square.getInhabitability(),0.001d);
	}
	
	@Test(expected = IllegalArgumentException.class)
	public void setTemperatureMergingConstant_wrongValue(){
		Square.setTemperatureMergingConstant(0.01);
	}
	
}
